/*
   DOES NOT USE THE BUILT-IN DETECTION FUNCTIONALITY!!

alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Microsoft Excel corrupted TABLE record clean up exploit attempt"; flowbits:isset,file.xls; flow:to_client,established; content:"|06 00|"; byte_jump:2,0,relative,little; content:"|36 02 10 00|"; within:4; metadata:policy security-ips drop, service http; reference:cve,2010-3232; reference:url,technet.microsoft.com/en-us/security/bulletin/MS10-080; classtype:attempted-user; sid:17762;)
*/
/*
 * Vuln Title: Microsoft Excel corrupted TABLE record clean up vulnerability
 *
 * Copyright (C) 2005-2010 Sourcefire, Inc. All Rights Reserved
 *
 * Written by Sojeong Hong, Sourcefire VRT shong@sourcefire.com>
 *
 * Auto-generated by shong
 *
 * This file may contain proprietary rules that were created, tested and
 * certified by Sourcefire, Inc. (the "VRT Certified Rules") as well as
 * rules that were created by Sourcefire and other third parties and
 * distributed under the GNU General Public License (the "GPL Rules").  The
 * VRT Certified Rules contained in this file are the property of
 * Sourcefire, Inc. Copyright 2005 Sourcefire, Inc. All Rights Reserved.
 * The GPL Rules created by Sourcefire, Inc. are the property of
 * Sourcefire, Inc. Copyright 2002-2005 Sourcefire, Inc. All Rights
 * Reserved.  All other GPL Rules are owned and copyrighted by their
 * respective owners (please see www.snort.org/contributors for a list of
 * owners and their respective copyrights).  In order to determine what
 * rules are VRT Certified Rules or GPL Rules, please refer to the VRT
 * Certified Rules License Agreement.
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG 1
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif

/* declare detection functions */
int rule17762eval(void *p);

/* declare rule data structures */
/* flowbits:isset "file.xls"; */
static FlowBitsInfo rule17762flowbits0 =
{
    "file.xls",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule17762option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule17762flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule17762flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule17762option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule17762flow1
    }
};
// content:"|06 00|", depth 0; 
static ContentInfo rule17762content2 = 
{
    (uint8_t *) "|06 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_NORMALIZED|CONTENT_RELATIVE, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule17762option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule17762content2
    }
};
/* byte_jump:size 2, relative, endian little; */
static ByteData rule17762byte_jump3 = 
{
    2, /* size */
    0, /* operator, byte_jump doesn't use operator! */
    0, /* value, byte_jump doesn't use value! */
    0, /* offset */
    
    0, /* multiplier */
    BYTE_LITTLE_ENDIAN|CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED|EXTRACT_AS_BYTE /* flags */
};

static RuleOption rule17762option3 = 
{
    OPTION_TYPE_BYTE_JUMP,
    {
        &rule17762byte_jump3
    }
};
// content:"6|02 10 00|", depth 4, relative, fast_pattern; 
static ContentInfo rule17762content4 = 
{
    (uint8_t *) "|00 36 02 10 00|", /* pattern (now in snort content format) */
    5, /* depth */
    -1, /* offset */
    CONTENT_RELATIVE|CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule17762option4 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule17762content4
    }
};

/* references for sid 17762 */
/* reference: cve "2010-3232"; */
static RuleReference rule17762ref1 = 
{
    "cve", /* type */
    "2010-3232" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/MS10-080"; */
static RuleReference rule17762ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/MS10-080" /* value */
};

static RuleReference *rule17762refs[] =
{
    &rule17762ref1,
    &rule17762ref2,
    NULL
};
/* metadata for sid 17762 */
/* metadata:service http, policy security-ips drop; */
static RuleMetaData rule17762service1 = 
{
    "service http"
};


//static RuleMetaData rule17762policy1 = 
//{
//    "policy security-ips drop"
//};

static RuleMetaData rule17762policy2 = 
{
    "policy max-detect-ips drop"
};

static RuleMetaData *rule17762metadata[] =
{
    &rule17762service1,
//    &rule17762policy1,
    &rule17762policy2,
    NULL
};

RuleOption *rule17762options[] =
{
    &rule17762option0,
    &rule17762option1,
    &rule17762option2,
    &rule17762option3,
    &rule17762option4,
    NULL
};

Rule rule17762 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       17762, /* sigid */
       12, /* revision */
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-OFFICE Microsoft Excel corrupted TABLE record clean up exploit attempt",     /* message */
       rule17762refs /* ptr to references */
       ,rule17762metadata
   },
   rule17762options, /* ptr to rule options */
   &rule17762eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};

/* detection functions */
// #if 0 // Don't compile the detection functions if they're not used
int rule17762eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *cursor_detect, *end_of_payload;
    
    uint16_t Ref_rwFirst;
    uint16_t Ref_rwLast;
    uint16_t rwInpRw;        
    uint16_t Ref_reserved2;

    uint8_t loopcounter = 0;

    if(sp == NULL)
        return RULE_NOMATCH;

    DEBUG_SO(printf("rule17762eval enter\n");)    

    // flowbits:isset "file.xls";
    if (processFlowbits(p, rule17762options[0]->option_u.flowBit) <= 0)
        return RULE_NOMATCH;
        
    // flow:established, to_client;
    if (checkFlow(p, rule17762options[1]->option_u.flowFlags) <= 0 )
        return RULE_NOMATCH;

    if (getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0)
        return RULE_NOMATCH;

    // FORMULA record (type 0x06) precedes TABLE record. 
    // content:"|06 00|", depth 0; relative;
    while (contentMatch(p, rule17762options[2]->option_u.content, &cursor_normal) > 0) {

        // DoS protection
        loopcounter++;
        if(loopcounter > 100)
           return RULE_NOMATCH;
        cursor_detect = cursor_normal;
        
        // skip FORMULA data part
        // byte_jump:size 2, relative, endian little;
        if (byteJump(p, rule17762options[3]->option_u.byte, &cursor_detect) > 0) {

            // TABLE record (type 0x236) with static data size 16.
            // content:"|00 36 02 10 00|", depth 5, distance -1, relative, fast_pattern;
            if (contentMatch(p, rule17762options[4]->option_u.content, &cursor_detect) > 0)
            {

                DEBUG_SO(printf("TABLE record is found\n");)
                if (cursor_detect + 10 > end_of_payload)
                    return RULE_NOMATCH;

                Ref_rwFirst = read_little_16(cursor_detect);
                DEBUG_SO(printf("Ref_rwFirst = 0x%04x\n", Ref_rwFirst);)
                cursor_detect += 2;
                                
                Ref_rwLast  = read_little_16(cursor_detect);
                DEBUG_SO(printf("Ref_rwLast = 0x%04x\n", Ref_rwLast);)
                cursor_detect += 4;
                
                Ref_reserved2  = read_little_16(cursor_detect);
                DEBUG_SO(printf("Ref_reserved2 = 0x%04x\n", Ref_reserved2);)
                cursor_detect += 2;
             
                //In the table record, Ref_reserved2 is the last 10 bits of the 2 byte flag field and it must be 0.
                if (Ref_reserved2 & 0x03FF)
                    continue;

                rwInpRw = read_little_16(cursor_detect);
                DEBUG_SO(printf("rwInpRw = 0x%04x\n", rwInpRw);)

                if (rwInpRw < Ref_rwFirst || rwInpRw > Ref_rwLast)
                    return RULE_MATCH;
            }
        }
    }
    
    return RULE_NOMATCH;
}
// #endif // 0 Don't compile the detection functions if they're not used
/*
Rule *rules[] = {
    &rule17762,
    NULL
};
*/
